﻿using DivaScript;
using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.IO;

namespace DivaScriptConv
{
    class DSC
    {
        //public static bool json = false;
        public static void Convert(string[] args, int duet = 1, bool to_aft = false)
        {
#if DEBUG
            // args = new string[] { "-i:ft", "test.dsc", "-o:a", "out.dsc", "-e", "exp.bin" };
            // args = new string[] { "-i:ft", "..\\Release\\Scripts\\pv_710_extreme.dsc", "-o:a", "pv_710_extreme2.dsc", "-e", "..\\Release\\PvExp\\exp_PV710.bin" };
#endif

#if PUBLIC
            var args_str = "";
            foreach (var i in args)
            {
                args_str = args_str + " ";
            }

            if (File.Exists("DivaScriptConv.exe"))
            {
                var process = new Process
                {
                    StartInfo = new ProcessStartInfo
                    {
                        FileName = "DivaScriptConv.exe",
                        Arguments = args_str,
                        UseShellExecute = false,
                        RedirectStandardOutput = true,
                        RedirectStandardError = true,
                        CreateNoWindow = true
                    }
                };
                process.Start();
                process.WaitForExit();
            }
            else
            {
                Console.WriteLine("ERROR : DivaScriptConv is unavailable!");
            }
            return;
#endif

#if (!PUBLIC)
            if (args.Length < 1)
            {
                var fn = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
                var fi = new FileInfo(fn).Name;
                Console.WriteLine("Converter for all Project Diva DSC (Diva Script Container) files.");
                Console.WriteLine("\nSupported input file format:");
                Console.WriteLine("    f   :   Project DIVA F DSC");
                Console.WriteLine("    f2  :   Project DIVA F 2nd DSC");
                Console.WriteLine("    dt  :   Project DIVA Dreamy Theater DSC");
                Console.WriteLine("    ft  :   Project DIVA Future Tone DSC");
                Console.WriteLine("    x   :   Project DIVA X DSC");
                Console.WriteLine("    o   :   Osu!Mania 4key");
                Console.WriteLine("\nSupported output file format:");
                Console.WriteLine("    f   :   Project DIVA F DSC");
                Console.WriteLine("    a   :   Project DIVA Arcade DSC");
                Console.WriteLine("    t   :   Project DIVA DivaScipt TXT");
                Console.WriteLine("\nUsage:");
                Console.WriteLine("    {0} -i:[format] [infile] -o:[format] [outfile] ... {{options}}", fi);
                Console.WriteLine("\nOptions:");
                Console.WriteLine("    -i:...  Input File");
                Console.WriteLine("    -o:...  Output File");
                Console.WriteLine("    -c f    Fix Chance Time");
                Console.WriteLine("    -c r    Remove Chance Time");
                Console.WriteLine("    -n m    Clean Multi Targets");
                Console.WriteLine("    -n h    Clean Hold Targets");
                Console.WriteLine("    -n s    Remove Slide Targets");
                Console.WriteLine("    -b      Is Big Edian");
                Console.WriteLine("    -e [..] PV Expression (Experimental)");
                Console.WriteLine("    -v      PV Video Only");
                Console.WriteLine("    -s      Single Load Model");
                Console.WriteLine("    -t [..] Trim Opcodes");
                Console.WriteLine("\nExample:");
                Console.WriteLine("    {0} -i:ft in.dsc -o:f out.dsc", fi);
            }
            if (args.Length == 0) return;

            bool from_json = false;
            string[] eoc = null;
            string cmd, fmi, fin, fmo, fou, fex;
            bool bed, rmc, rmh, rmm, rms, fmc, pvo, smt;
            cmd = fmi = fin = fmo = fou = fex = String.Empty;
            bed = rmc = rmh = rmm = rms = fmc = pvo = smt = false;
            for (int i = 0; i < args.Length; i++)
            {
                var a = args[i];
                if (a.Length > 1 && a.StartsWith("-"))
                {
                    cmd = a.Substring(1, 1);
                    switch (cmd)
                    {
                        case "c": // Chance Time
                            if (i < args.Length - 1) i++;
                            var c = args[i].ToLower();
                            if (c.Equals("r")) rmc = true; // CleanChanceTime
                            else if (c.Equals("f")) fmc = true; // FixChanceTime
                            break;
                        case "n": // Notes Cleaning
                            if (i < args.Length - 1) i++;
                            var n = args[i].ToLower();
                            if (n.Contains("m")) rmm = true; // CleanMultiTargets
                            if (n.Contains("h")) rmh = true; // CleanHoldTargets
                            if (n.Contains("s")) rms = true; // CleanSlideTargets
                            break;
                        case "b": // Is Big Edian
                            bed = true; break;
                        case "i": // Input File
                            if (a.Length < 4) break;
                            fmi = a.Substring(3);
                            if (i < args.Length - 1) i++;
                            fin = args[i]; break;
                        case "o": // Output File
                            if (a.Length < 4) break;
                            fmo = a.Substring(3);
                            if (i < args.Length - 1) i++;
                            fou = args[i]; break;
                        case "e": // Expression File
                            if (i < args.Length - 1) i++;
                            fex = args[i]; break;
                        case "v": // PV Video Only
                            pvo = true; break;
                        // case "s": // Smart Processing
                        //     smt = true; break;
                        case "t": // Trim Opcodes
                            if (i < args.Length - 1) i++;
                            eoc = args[i].Split(','); break;
                        default:
                            break;
                    }
                    continue;
                }
            }
            if (String.IsNullOrEmpty(fmi) || String.IsNullOrEmpty(fin) || String.IsNullOrEmpty(fmo) || String.IsNullOrEmpty(fou))
            {
                Console.WriteLine("Please check your arguments.");
                return;
            }
            Format fmt;
            if (!File.Exists(fin))
            {
                Console.WriteLine("Specified file is not existed.");
                return;
            }
            if (File.GetAttributes(fin).HasFlag(FileAttributes.Directory))
            {
                Console.WriteLine("Source must be a valid file.");
                return;
            }

            bool from_osu = false;

            switch (fmi)
            {
                case "dt":
                    fmt = Format.F;
                    break;
                case "f":
                    fmt = Format.F;
                    break;
                case "f2":
                    fmt = Format.F2;
                    break;
                case "ft":
                    fmt = Format.FT;
                    break;
                case "x":
                    fmt = Format.X;
                    break;
                case "jsonFT":
                    fmt = Format.FT;
                    from_json = true;
                    break;
                case "o":
                    fmt = Format.FT;
                    from_osu = true;
                    break;
                default:
                    Console.WriteLine("Invalid format. Please check your input.");
                    return;
            }
            var cvt = new Converter(fin, fou, fmt);
            // cvt.PvName = fin;
            // cvt.PvFieldData = "pv_field.txt";
            cvt.IsBigEdian = bed;
            cvt.CleanChanceTime = rmc;
            cvt.FixChanceTime = fmc;
            cvt.CleanHoldTargets = rmh;
            cvt.CleanMultiTargets = rmm;
            cvt.CleanSlideTargets = rms;
            cvt.PvExpression = fex;
            cvt.PvTargetsOnly = pvo;
            cvt.SingleLoad = smt;
            cvt.performers = duet;

            if (to_aft)
                cvt.to_aft = true;

            cvt.from_json = from_json;
            cvt.from_osu = from_osu;

            if (eoc != null && eoc.Length > 1)
                cvt.OpcodeExcludeList = eoc;
            switch (fmo)
            {
                case "ft":
                    cvt.ConvertToFt();
                    break;
                case "f":
                    cvt.ConvertToF();
                    break;
                case "a":
                    cvt.ConvertToA();
                    break;
                case "t":
                    cvt.ConvertToTxt();
                    break;
                default:
                    Console.WriteLine("Invalid format. Please check your input.");
                    return;
            }
            bool json = false;

            if (File.Exists("dbg"))
            {
                json = true;
            }

            if (json)
            {
                JsonSerializer serializer = new JsonSerializer();
                serializer.NullValueHandling = NullValueHandling.Ignore;

                using (StreamWriter sw = new StreamWriter("dsc_json\\" + Path.GetFileNameWithoutExtension(cvt._in) + "_after.txt"))
                using (JsonWriter writer = new JsonTextWriter(sw))
                {
                    serializer.Serialize(writer, cvt._pv);
                }
            }

            Console.WriteLine("Converted " +  cvt._in);
#if DEBUG
            //Console.ReadKey();
#endif

#endif
        }

    }
}
